import * as THREE from '../../build/three.module.js';

import { OrbitControls } from '../../jsm/controls/OrbitControls.js';
import { TeapotBufferGeometry } from '../../jsm/geometries/TeapotBufferGeometry.js';

import {
  NodeFrame,
  FloatNode,
  ColorNode,
  ConstNode,
  ExpressionNode,
  MathNode,
  OperatorNode,
  TimerNode,
  PhongNodeMaterial
} from '../../jsm/nodes/Nodes.js';

// 全局变量
const meshs = [];
let rtTexture = null, rtMaterial = null;
const frame = new NodeFrame();

const scene = new THREE.Scene();

const clock = new THREE.Clock();

const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 1000);
camera.position.x = 0;
camera.position.y = 200;
camera.position.z = -300;

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(devicePixelRatio);
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 50;
controls.maxDistance = 400;

scene.add( new THREE.AmbientLight(0x464646) );

const dl1 = new THREE.DirectionalLight(0xffddcc, 1);
dl1.position.set(1, 0.75, 0.5);
scene.add(dl1);

const dl2 = new THREE.DirectionalLight(0xccccff, 1);
dl2.position.set(1, -0.75, -0.5);
scene.add(dl2);

const teapotGeo = new TeapotBufferGeometry(15, 18);

const itemsonrow = 10;

// 设置网格对象材质
const updateMaterial = mesh => {
  if (mesh.material) mesh.material.dispose();

  if (rtTexture) {
    rtTexture.dispose();
    rtTexture = null;
  }

  if (rtMaterial) {
    rtMaterial.dispose();
    rtMaterial = null;
  }

  const mtl = new PhongNodeMaterial();

  const time = new TimerNode();
  const speed = new FloatNode( Math.random() );

  const color = new ColorNode( Math.random() * 0xffffff );

  const timeSpeed = new OperatorNode(
    time,
    speed,
    OperatorNode.MUL
  );

  const sinCycleInSecs = new OperatorNode(
    timeSpeed,
    new ConstNode( ConstNode.PI2 ),
    OperatorNode.MUL
  );

  const cycle = new MathNode( sinCycleInSecs, MathNode.SIN );

  const cycleColor = new OperatorNode(
    cycle,
    color,
    OperatorNode.MUL
  );

  const cos = new MathNode( cycleColor, MathNode.SIN );

  mtl.color = new ColorNode(0);
  mtl.emissive = cos;

  const transformer = new ExpressionNode( "position + 0.0 * " + Math.random(), 'vec3', [] );
  mtl.transform = transformer;

  mtl.build();

  mesh.material = mtl;
}

for(let i = 0; i < itemsonrow * itemsonrow; i += 1) {
  const mesh = new THREE.Mesh(teapotGeo);

  mesh.position.x = 50 * (i % itemsonrow) - 50 * itemsonrow / 2;
  mesh.position.y = 50 * Math.floor(i / itemsonrow) - 150;
  updateMaterial(mesh);
  scene.add(mesh);
  meshs.push(mesh);
}

renderer.compile( scene, camera );

// 驱动
const animate = () => {
  const delta = clock.getDelta();

  frame.update(delta);

  for(let i = 0; i < meshs.length; i += 1) {
    const mesh = meshs[i];

    frame.updateNode(mesh.material);
  }

  renderer.render(scene, camera);

  requestAnimationFrame(animate);
}
animate();

// 事件处理
const onWindowResize = () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(innerWidth, innerHeight);
  
  if (rtTexture) {
    rtTexture.setSize(innerWidth, innerHeight);
  }
}
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
